package main

import (
	"fmt"
	"sync"
)

/*
前面我们采用sleep来保证子协程执行完，父协程才退出，但是在实际中我们并不知道子协程需要多久才执行完、
所以才用waitgroup来阻塞等待，让子goroutine通知父的自己执行完了，然后父的知道执行完了才退出
sync.WaitGroup{}用于goroutine的执行等待，Add方法和Done方法需要配套执行，增加多少个就要Done多少，Wait放在最后

1. WaitGroup 简介
WaitGroup 是 Go 语言标准库 sync 包中的一个并发同步工具，它用于协调主 goroutine 与多个工作 goroutine 的执行。
通过计数器跟踪还未完成的工作 goroutine 的数量，WaitGroup 能够确保主 goroutine 在所有工作 goroutine 完成之前不会继续执行。
2. 工作原理
Add(delta int): 此方法用来设置或更新 WaitGroup 的计数器。如果 delta 是正数，表示增加相应数量的等待任务；如果 delta 是负数，表示减少相应数量的等待任务。
Done(): 工作 goroutine 完成任务后调用此方法，内部通过调用 Add(-1) 来减少计数器的值。
Wait(): 主 goroutine 调用此方法，如果计数器不为零，则阻塞等待，直到所有工作 goroutine 完成（即计数器归

*/

func main() {
	// 声明并实例化一个WaitGroup，会自动实例化，按格式写
	wg := sync.WaitGroup{}
	// 添加需要监控执行完的goroutine的个数，这个需要和done配对出现，不然会报死锁，增加了多少个就需要done多少次
	wg.Add(20)
	for i := 0; i < 20; i++ {
		go func(i int) {
			//采用延迟函数，在函数执行的最后关闭监控器
			defer wg.Done()
			fmt.Println("groutine", i)
		}(i)
	}
	// 等待goroutine都执行完成
	wg.Wait()
}
